ReturnType<T> 구현하기
type MyReturnType<T> = T extends (...args: any[]) => infer B ? B : never;
Omit<T, K> 구현하기
type MyOmit<T, K> = {
[key in keyof T as key extends K ? never : key]: T[key];
}
여기서 as 의 역할, key에 대한 조건을 후술할 수 있도록 다리 역할을 한다.
as 가 없으면 일단 property로 인식되기 때문에 이후에 오는 conditional이 의도대로 동작하지 않는다.
T의 속성중 K를 readonly로 설정하는 타입 구현, K가 주어지지 않으면 전부 readonly
type MyReadonly2<T, K = keyof T> = {
readonly [key in keyof T as key extends K ? key: never]: T[key];
} & {
[key in keyof T as key extends K ? never : key]: T[key];
}
Omit<T,K> 을 이용하여 작성할 수 있다.
generic작성과 마찬가지로 타입이 명시되지 않은 경우 기본값을 지정해줄 수 있다.
오브젝트와 오브젝트 내 모든 오브젝트를 재귀적으로 readonly로 만드는 제너릭 타입형을 구현하라
type DeepReadonly<T> = {
readonly [key in keyof T]: T[key] extends Record<string, unknown> ? DeepReadonly<T[key]> : T[key];
};
Record<string, unknown> vs. Record<string, any> vs. object ???
generic TupleToUnion<T> 구현.
타입 조건문 사용시 분배 법칙에 의해 각 T[number]의 Union으로 완성된다.
type TupleToUnion<T> = T extends any[] ? T[number]: never;
Chaining을 통해서 속성의 확장이 가능한 타입/클래스 만들기. get을 이용하여 완성된 형태를 반환
type Chainable<T extends {} = {}> = {
option<TKey extends string, TVal>(key: TKey, value: TVal): Chainable<{
[key in keyof T as key extends TKey ? never: key]: T[key];
} & {
[key in TKey]: TVal;
}>
get(): IntersectionMerge<T>
}
type IntersectionMerge<Tinter> = Tinter extends Record<string, any> ? {
[key in keyof Tinter]: Tinter[key]
} : never;
declare const config: Chainable
const result = config
.option('foo', 123)
.option('name', 'type-channelges')
.option('bar', {value: 'Hello World'})
type Last<T extends any[]> = T extends [...infer _, infer Last] ? Last : T[0]
type Pop<T extends any[]> = T extends [...infer R, any] ? R : []